// Copyright (C) 2016 All rights reserved.
// Author: liufeng11@letv.com (Liu Feng)
// Description:
#include "HaarFontFeatureExtractor.h"

#define I(b) (b?255:0)
void HaarFontFeatureExtractor::ExtractFeature(const unsigned char* data, std::vector<double>* feature) {
  if (!feature || !data) return;

    // Blur

    double centerWeight = 0.0177;
    double w1 = 0.0158;
    double w2 = 0.0167;
    double gray[ROWS*COLS] = { 0 };
    for (int i = 0; i < ROWS; ++i) {
      for (int j = 0; j < COLS; ++j) {
        gray[i*COLS+j] = centerWeight*I(P(data, i, j));
        gray[i*COLS+j] += w1*I(P(data, i-1, j-1));
        gray[i*COLS+j] += w2*I(P(data, i-1, j));
        gray[i*COLS+j] += w1*I(P(data, i-1, j+1));
        gray[i*COLS+j] += w2*I(P(data, i, j+1));
        gray[i*COLS+j] += w1*I(P(data, i+1, j+1));
        gray[i*COLS+j] += w2*I(P(data, i+1, j));
        gray[i*COLS+j] += w1*I(P(data, i+1, j-1));
        gray[i*COLS+j] += w2*I(P(data, i, j-1));
      }
    }

    // Calcualate integral image
    double I[ROWS*COLS] = { 0 };
   
    for (int i = 0; i < ROWS; ++i) {
      double s[COLS] = { 0 };
      s[0] = gray[0];
      for (int j = 1; j < COLS; ++j) {
        s[j] = s[j-1] + P(gray, i, j);
        if (i != 0)
          P(I, i, j) = P(I, i-1, j) + s[j]; 
        else
          P(I, i, j) = s[j];
      }
    }

    // scale at 1/16, 1/8, 1/4, 1/2
    // ExtractHaarFeature(I, ROWS, COLS, 16, feature);
    ExtractHaarFeature(I, ROWS, COLS, 8, feature);
    ExtractHaarFeature(I, ROWS, COLS, 6, feature);
    ExtractHaarFeature(I, ROWS, COLS, 4, feature);
    ExtractHaarFeature(I, ROWS, COLS, 2, feature);
    ExtractHaarFeature(I, ROWS, COLS, 1, feature);
    
  }


  void HaarFontFeatureExtractor::ExtractHaarFeature(const double* I, int rows, int cols, int scale, std::vector<double>* v) {
    if (!v) return;
    double dx, dy;

    dx = (double)cols/scale;
    dy = (double)rows/scale; 
    for (int y = -1; y < rows-dy; ++y) {
      for (int x = -1; x < cols-dx; ++x) {
        double i = y;
        double j = x;
        double xMid = j + dx/2;
        double yMid = i + dy/2; 
        double right = j + dx;
        double bottom = i + dy;
        double sx2 = P(I, bottom, right) - P(I, bottom, xMid) - P(I, i, right) + P(I, i, xMid);
        double sx1 = P(I, bottom, xMid) - P(I, bottom, j) - P(I, i, xMid) + P(I, i, j);
        double sy2 = P(I, bottom, right) - P(I, bottom, j) - P(I, yMid, right) + P(I, yMid, j);
        double sy1 = P(I, yMid, right) - P(I, yMid, j) - P(I, i, right) + P(I, i, j);
        // double sxy2 = P(I, bottom, right) - P(I, bottom, xMid) - P(I, yMid, right) + P(I, yMid, xMid) + P(I, yMid, xMid) - P(I, yMid, j) - P(I, i, xMid) + P(I, i, j);
        double sxy2 = P(I, bottom, right) - P(I, bottom, xMid) - P(I, yMid, right) + 2*P(I, yMid, xMid) - P(I, yMid, j) - P(I, i, xMid) + P(I, i, j);
        // double sxy1 = P(I, bottom, xMid) - P(I, bottom, j) - P(I, yMid, xMid) + P(I, yMid, j) + P(I, yMid, right) - P(I, yMid, xMid) - P(I, i, right) + P(I, i, xMid);
        double sxy1 = P(I, bottom, xMid) - P(I, bottom, j) - 2*P(I, yMid, xMid) + P(I, yMid, j) + P(I, yMid, right) - P(I, i, right) + P(I, i, xMid);

        // double s = P(I, bottom, right) - P(I, bottom, j) - P(I, i, right) + P(I, i, j);
        // double sxx = P(I, bottom, j+dy/3*2) - P(I, bottom, j+dy/3) - P(I, i, j+dy/3*2) + P(I, i, j+dy/3);
        // double syy = P(I, i+dx/3*2, right) - P(I, i+dx/3*2, j) - P(I, i+dx/3, right) + P(I, i+dx/3, j);
        v->push_back(sx2 - sx1);
        v->push_back(sy2 - sy1);
        v->push_back(sxy2 - sxy1);
        // v->push_back(s-2*sxx);
        // v->push_back(s-2*syy);
      }
    }
  }
